﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Data;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data.Common;
using System.Data.SqlClient;

namespace Guru.Data
{
    [Serializable]
    public class GuruParameter : ICloneable
    {
        public string ParameterName { get; set; }
        public object ParameterValue { get; set; }
        public object ParameterType { get; set; }
        public int ParameterSize { get; set; }
        public bool IsOutParameter { get; set; }
        public object[] ParamsList { get; set; }


        public GuruParameter()
        {
            ParameterName = string.Empty;
            ParameterValue = null;
            ParameterType = null;
            ParameterSize = 0;
            IsOutParameter = false; //default is Input Parameter
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GuruParameter"/> class.
        /// </summary>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="parameterValue">The parameter value.</param>
        /// <param name="parameterType">Type of the parameter.</param>
        public GuruParameter(string parameterName, object parameterValue, object parameterType)
        {
            ParameterName = parameterName;
            ParameterValue = parameterValue;
            ParameterType = parameterType;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GuruParameter"/> class.
        /// </summary>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="parameterValue">The parameter value.</param>
        /// <param name="parameterType">Type of the parameter.</param>
        /// <param name="parameterDirection">if set to <c>false</c> OUTPUT, if set to <c>true</c> INPUT</param>
        public GuruParameter(string parameterName, object parameterValue, object parameterType, int parameterSize, bool isOutParam)
            : this(parameterName, parameterValue, parameterType)
        {
            ParameterSize = parameterSize;
            IsOutParameter = isOutParam;

        }

        /// <summary>
        /// Clones this instance.
        /// </summary>
        /// <returns></returns>
        public GuruParameter Clone()
        {
            return new GuruParameter
            {
                ParameterName = ParameterName,
                ParameterType = ParameterType,
                ParameterValue = ParameterValue,
                IsOutParameter = IsOutParameter
            };
        }


        #region ICloneable Members

        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        /// A new object that is a copy of this instance.
        /// </returns>
        object ICloneable.Clone()
        {
            return Clone();
        }

        #endregion
    }

    [Serializable]
    public class GuruParameterCollection : CollectionBase, ICloneable
    {
        public GuruParameterCollection()
        {

        }
        public GuruParameter this[int index]
        {
            get { return ((GuruParameter)List[index]); }
            set { List[index] = value; }
        }

        public object this[string name]
        {
            get { return FindGuruParameterValueByName(name); }
        }

        /// <summary>
        /// Add the specified GuruParameter object.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The index of GuruParameter object.</returns>
        public int Add(GuruParameter value)
        {
            return (List.Add(value));
        }

        /// <summary>
        /// Add the specified parameter name.
        /// </summary>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="parameterValue">The parameter value.</param>
        /// <param name="parameterType">Type of the parameter.</param>
        /// <returns>The index of GuruParameter object.</returns>
        public GuruParameterCollection Add(string parameterName, object parameterValue, object parameterType)
        {
            var parameter = new GuruParameter
            {
                ParameterName = parameterName,
                ParameterValue = parameterValue,
                ParameterType = parameterType
            };
            List.Add(parameter);

            return this;
        }

        /// <summary>
        /// Add the specified parameter name.
        /// </summary>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="parameterValue">The parameter value.</param>
        /// <param name="parameterType">Type of the parameter.</param>
        /// <param name="isOutParameter">if true, this parameter is out parameter.</param>
        /// <returns>The index of GuruParameter object.</returns>
        public GuruParameterCollection Add(string parameterName, object parameterValue, object parameterType, bool isOutParameter)
        {
            var parameter = new GuruParameter
            {
                ParameterName = parameterName,
                ParameterValue = parameterValue,
                ParameterType = parameterType,
                IsOutParameter = isOutParameter
            };
            List.Add(parameter);

            return this;
        }

        public int IndexOf(GuruParameter value)
        {
            return (List.IndexOf(value));
        }

        public void Insert(int index, GuruParameter value)
        {
            List.Insert(index, value);
        }

        public void Remove(GuruParameter value)
        {
            if (value != null)
                List.Remove(value);
        }

        public bool Contains(GuruParameter value)
        {
            // If value is not of type Test, this will return false.
            return (List.Contains(value));
        }

        public GuruParameter FindGuruParameterByName(string paramName, bool isCaseSensitive)
        {
            for (int i = 0; i < List.Count; i++)
            {
                GuruParameter param = (GuruParameter)List[i];
                if (string.Compare(param.ParameterName, paramName, isCaseSensitive) == 0) return param;
            }

            return null;
        }

        public object FindGuruParameterValueByName(string paramName)
        {
            for (int i = 0; i < List.Count; i++)
            {
                GuruParameter param = (GuruParameter)List[i];
                if (param.ParameterName.ToString().Equals(paramName, StringComparison.CurrentCultureIgnoreCase))
                {
                    return param.ParameterValue;
                }
            }
            return string.Empty;
        }

        public string ToStringWithParamInfo()
        {
            StringBuilder Temp = new StringBuilder();
            foreach (GuruParameter p in this.List)
            {
                Temp.Append(string.Format("{0}={1}; ", p.ParameterName, p.ParameterValue));
            }
            return Temp.ToString();
        }

        /// <summary>
        /// Clones the collection.
        /// </summary>
        /// <returns></returns>
        public GuruParameterCollection CloneCollection()
        {

            GuruParameterCollection list = new GuruParameterCollection();
            for (int i = 0; i < List.Count; i++)
                list.Add((GuruParameter)List[i]);

            return list;
        }

        /// <summary>
        /// Aas the parameter for paging interface.
        /// </summary>
        /// <param name="isPaging">if set to <c>true</c> [is paging].</param>
        /// <param name="isCountPageTotal">if set to <c>true</c> [is count page total].</param>
        /// <param name="pageNo">The page no.</param>
        /// <param name="pageSize">Size of the page.</param>
        /// <param name="orderExp">The order exp.</param>
        /// <param name="filterExp">The filter exp.</param>
        public void AddPagingParameters(
            bool isPaging, bool isCountPageTotal, int pageNo, int pageSize, string orderExp, string filterExp)
        {
            this.Add(new GuruParameter { ParameterName = "@IsPaging", ParameterValue = isPaging, ParameterType = DbType.Boolean });
            this.Add(new GuruParameter { ParameterName = "@IsCountPageTotal", ParameterValue = isCountPageTotal, ParameterType = DbType.Boolean });
            this.Add(new GuruParameter { ParameterName = "@PageNo", ParameterValue = pageNo, ParameterType = DbType.Int32 });
            this.Add(new GuruParameter { ParameterName = "@PageSize", ParameterValue = pageSize, ParameterType = DbType.Int32 });
            this.Add(new GuruParameter { ParameterName = "@stOrder", ParameterValue = orderExp, ParameterType = DbType.AnsiString });
            this.Add(new GuruParameter { ParameterName = "@stFilter", ParameterValue = filterExp, ParameterType = DbType.AnsiString });
        }

        /// <summary>
        /// Clears the paging parameters.
        /// </summary>
        public void ClearPagingParameters()
        {
            GuruParameter fp = this.FindGuruParameterByName("@IsPaging", false);
            this.Remove(fp);
            fp = this.FindGuruParameterByName("@IsCountPageTotal", false);
            this.Remove(fp);
            fp = this.FindGuruParameterByName("@PageNo", false);
            this.Remove(fp);
            fp = this.FindGuruParameterByName("@PageSize", false);
            this.Remove(fp);
            fp = this.FindGuruParameterByName("@stOrder", false);
            this.Remove(fp);
            fp = this.FindGuruParameterByName("@stFilter", false);
            this.Remove(fp);
        }


        #region ICloneable Members

        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        /// A new object that is a copy of this instance.
        /// </returns>
        public object Clone()
        {
            return CloneCollection();
        }

        #endregion
    }

    public static class ParameterExtension
    {
        public static void AddInParameter(this Database database, DbCommand dbCommand, GuruParameter param)
        {
            database.AddInParameter(dbCommand, param.ParameterName, param.ParameterType.GetDbType(), param.ParameterValue);
        }

        public static void AddOutParameter(this Database database, DbCommand dbCommand, GuruParameter param)
        {
            database.AddOutParameter(dbCommand, param.ParameterName, param.ParameterType.GetDbType(), param.ParameterSize);
        }

        public static void AddParameter(this Database database, DbCommand dbCommand, GuruParameter param)
        {
            database.AddParameter(dbCommand, param.ParameterName, param.ParameterType.GetDbType(), param.IsOutParameter ? ParameterDirection.Output : ParameterDirection.Input, param.ParameterName, DataRowVersion.Default, null);
        }

        public static DbType GetDbType(this object parameterType)
        {
            return (DbType)Enum.ToObject(typeof(DbType), parameterType);
        }

        public static DataTable ToDataTable(this DataSet dataList)
        {
            if (dataList.Tables.Count > 0)
                return dataList.Tables[0];
            return null;
        }
    }

}
